//
// Created by LiuYou on 2021/8/19.
//

#include <cstring>
#include <cerrno>
#include "CGI.hpp"
#include "ProcessPool.hpp"


int CGIConnect::epollFd = -1;


CGIConnect::CGIConnect() : sockFd(), readIdx(), buf(), address() {}

void CGIConnect::init(int epollFd_, int sockFd, const sockaddr_in& clientAddress) {
    epollFd = epollFd_;
    this->sockFd = sockFd;
    this->address = clientAddress;
    memset( buf, '\0', BUFFER_SIZE );
    readIdx = 0;
}

void CGIConnect::process() {
    int idx = 0;
    /* 循环读取和分析客户数据。*/
    while (true) {
        idx = readIdx;
        ssize_t rcvByteNum = recv( sockFd, buf + idx, BUFFER_SIZE - 1 - idx, 0 );
        /* 如果读操作发生错误, 则关闭客户连接。但如果是暂时无数据可读, 则退出循环。*/
        if (rcvByteNum < 0) {
            if (errno != EAGAIN) {
                removeFd( epollFd, sockFd );
            }
            break;
        }
            /* 如果对方关闭连接, 则服务器也关闭连接。*/
        else if (rcvByteNum == 0) {
            removeFd( epollFd, sockFd );
            break;
        } else {
            readIdx += rcvByteNum;
            printf( "user content is: %s\n", buf );
            for (; idx < readIdx; ++idx) {
                if ((idx >= 1) && (buf[idx - 1] == '\r') && (buf[idx] == '\n')) {
                    break;
                }
            }
            /* 如果没有遇到字符 \r\n , 则需要读取更多客户数据。*/
            if (idx == readIdx) {
                continue;
            }
            buf[idx - 1] = '\0';

            char* fileName = buf;
            /* 判断客户要运行的CGI程序是否存在。*/
            if (access( fileName, F_OK ) == -1) {
                removeFd( epollFd, sockFd );
                break;
            }
            /* 创建子进程来执行CGI程序。*/
            pid_t pid = fork();
            if (pid == -1) {
                removeFd( epollFd, sockFd );
                break;
            } else if (pid > 0) {
                /* 父进程只需关闭连接。*/
                removeFd( epollFd, sockFd );
                break;
            } else {
                /* 子进程将标准输出定向sockFd, 并执行CGI程序。*/
                close( STDOUT_FILENO );
                dup( sockFd );
                execl( buf, buf, 0 );
                exit( 0 );
            }
        }
    }
}

CGIConnect::~CGIConnect() = default;
